#ifndef _ModelCtrl_H_
#define _ModelCtrl_H_

#include "Common.h"
#include "defs.h"
#include "ocl.h"
#include "BaseHandle.h"
//#include "Legend.h"
#include "Mesh.h"
#include "Field.h"
#include "RContext.h"
#include "GraphicElem.hpp"
#include "CutPlane.h"
#include "../utils/fv_exception.h"

// stl, system
#include<string>
#include<stdexcept>
#include<cassert>


namespace FemViewer
{

	// Forword declarations
	class  Object;
	class  ViewManager;
	struct SolutionData;
		
	const char operations[] = {'r','l','c','f'};

	class ModelCtrl //: public mfvBaseObject
	{
#ifdef PARALLEL
		// Store info
#endif

		//friend class mfvWindow;
		friend ModelCtrl & ModelCtrlInst(void);
	public:
		enum eCommnad {
			NOTHING   = -1,
			INIT	  =  0,
			INITMESH  =  1,
			INITFIELD,
			UPDATE,
			REFRESH,
			RELOAD,
			LEGCHANGE,
			CUTPLANECHANGE,
			GENERATE_NEW_MESH,
			GENERATE_NEW_FIELD,
			CLEAR, 
	    };
		SolutionData CurrentSolution;
	public:
		// Dtr
		~ModelCtrl();
		
		bool Do(const eCommnad oper,const std::string& str="");
		void Reset(bool eraseall = false);
		void Clear();
		void Destroy();
		void Draw();
		void SetMeshChange() { _meshChange = true; }
		void SetFieldChange() { _fieldChange = true; }
		void SetLegendChange() { _legendChange = true; }
		void SetCutPlaneChange() { _solutionChange = true; }
	protected:
		// Ctr
		explicit ModelCtrl();
		//TArrayPtrs<BaseHandle*,10> _objArray;
		Mesh      _mesh;
		Field	  _field;
		RContext* _pRC;
		//typedef TArrayPtrs<BaseHandle*,10>::size_type size_type;
		//Object&	  _modelGL;
		int&		_mId;  // current mesh id
		int&		_fId;  // current field id
		bool	  _meshChange;
		bool	  _fieldChange;
		bool	  _legendChange;
		bool	  _solutionChange;
		//vGEL2d    _vEGL;
		CutPlane  _curPlane;
		int       _meshType;
		int       _approxType;
		//Legend	  _currLegend;
		host_info_id _hosts;
#ifdef PARALLEL
		int 	  _procId;
		int		  _nrProcesses;
#endif

//	private:
	public:				
		Field* GetCurrentField() { return &_field; 
   //     	FV_ASSERT(_objArray[_fId]->type() & FieldHandle);
			//return reinterpret_cast<Field*>(_objArray.at(_fId));
        }

        Mesh* GetCurrentMesh() { return &_mesh;
			//if (_mId < 0) return NULL;
			//FV_ASSERT(_objArray[_mId]->type() & MeshHandle);
   //     	return reinterpret_cast<Mesh*>(_objArray.at(_mId));
        }		

		bool& MeshChange() { return _meshChange; }
		const bool& MeshCnage() const { return _meshChange; }

		bool& FieldChange() { return _fieldChange; }
		const bool& FieldChange() const { return _fieldChange; }

		bool& LegendChange() { return _legendChange; }
		const bool& LegendChange() const { return _legendChange; }

		CutPlane& GetCutPlane() { return _curPlane; }

		inline int GetMeshModuleType() const { return Mesh::GetMeshModuleType(); }
		inline int GetApproximationType() const { return Field::GetApproximationType(); }

		//Legend& GetLegend() { return _currLegend; }
	private:

		bool InitMesh(const std::string& file_name_);
		bool InitField(Mesh* parent_mesh_,const std::string& file_name_="",const HandleType type_=Unknown);

		void EraseMesh(const int& idx_);
		void EraseField(const int& idx_);

		template<class TEntity>
	    TEntity* GetEntity(const int idx_,const char* name_);

		template<class TMap, class T>
		inline T* GetTPtr(TMap& map_, const int & id_);
		template<class T>
		int RenderColoredLines();

		void BeforeRender();
		void AfterRender();
		bool SetBoundaryElems();
		int  TestConnection() const;
		int  InitHosts(int numHosts);

	private:
		// Block use of them
		ModelCtrl(const ModelCtrl&);
		ModelCtrl& operator=(const ModelCtrl&);
	};

	// Get the object entity.
	// If idx < 0 then create new object, if not get existing one.
	// If name_ is null then get it by index, if not read from file specified by name_.
/*	template<class TEntity>
	TEntity* ModelCtrl::GetEntity(const int idx_,const char* name_=NULL)
	{
		try
		{
			TEntity entt;
			if (idx_ < 0)
			{
				if (name_==NULL)
					entt = new TEntity;
				else
					entt = new TEntity(std::string(name_));
				assert(entt!=0);
				if (!_objArray.Register(entt)) throw fv_exception("Can't register mesh");
				return entt;
			}
			else
			{
				return _objArray.getbyID(idx);
			}
		}catch(std::ex ex )
		{

		}
		return NULL;
	}*/

	template<class TMap,class T>
	T* ModelCtrl::GetTPtr(TMap& map_, const int & id_)
	{
	 // check if argument already processed and stored in correct type
		/*if ( map_.end() != (_it = map_.find( id_)))
		{
			if ( (*(_it->second.first)) == typeid( T) ) 
			{
				return (T*) _it->second.second;
			}
		}
		else {
			T* tmp = new T;
              // add the token element pair to map of already converted values
                map_[id_] = std::make_pair( &(typeid( T)), (void*) tmp);

                return tmp;
		}*/

		// failed, argument not available
		return NULL;
	}

	extern ModelCtrl& ModelCtrlInst(void); 



} // end namespace FemViewer
#endif /* _ModelCtrl_CONTROLER_HPP_
*/
